/**
 * @author lantian
 */

$(function () {
    $.keywords = [
        "_blank",
        "_parent",
        "_self",
        "_top",
        "abbr",
        "accesskey",
        "acronym",
        "address",
        "ancestor",
        "ancestor-or-self",
        "and",
        "animationend",
        "animationiteration",
        "animationstart",
        "applet",
        "area",
        "article",
        "aside",
        "attribute",
        "audio",
        "base",
        "basefont",
        "bdi",
        "bdo",
        "big",
        "blockquote",
        "body",
        "br",
        "bubbles",
        "button",
        "cancelable",
        "canvas",
        "caption",
        "center",
        "child",
        "cite",
        "class",
        "click",
        "code",
        "col",
        "colgroup",
        "command",
        "contains",
        "contenteditable",
        "contextmenu",
        "currentTarget",
        "data",
        "datalist",
        "dd",
        "del",
        "descendant",
        "descendant-or-self",
        "details",
        "dfn",
        "dialog",
        "dir",
        "div",
        "dl",
        "draggable",
        "dropzone",
        "dt",
        "em",
        "embed",
        "eventPhase",
        "fieldset",
        "figcaption",
        "figure",
        "following-sibling::",
        "following::",
        "font",
        "footer",
        "form",
        "frame",
        "frameset",
        "h1",
        "h2",
        "h3",
        "h4",
        "h5",
        "h6",
        "head",
        "header",
        "height",
        "hidden",
        "hr",
        "href",
        "html",
        "id",
        "iframe",
        "img",
        "input",
        "ins",
        "kbd",
        "keygen",
        "label",
        "lang",
        "legend",
        "li",
        "link",
        "main",
        "map",
        "mark",
        "maxlength",
        "menu",
        "menuitem",
        "meta",
        "meter",
        "minlength",
        "name",
        "namespace",
        "nav",
        "noframes",
        "noscript",
        "object",
        "ol",
        "onabort",
        "onabort",
        "onafterprint",
        "onbeforeprint",
        "onbeforeunload",
        "onblur",
        "oncanplay",
        "oncanplaythrough",
        "onchange",
        "onclick",
        "oncontextmenu",
        "oncopy",
        "oncut",
        "ondblclick",
        "ondrag",
        "ondragend",
        "ondragenter",
        "ondragleave",
        "ondragover",
        "ondragstart",
        "ondrop",
        "ondurationchange",
        "onemptied",
        "onended",
        "onerror",
        "onerror",
        "onfocus",
        "onfocusin",
        "onfocusout",
        "onhashchange",
        "oninput",
        "onkeydown",
        "onkeypress",
        "onkeyup",
        "onload",
        "onloadeddata",
        "onloadedmetadata",
        "onloadstart",
        "onmessage",
        "onmousedown",
        "onmouseenter",
        "onmouseleave",
        "onmousemove",
        "onmouseout",
        "onmouseover",
        "onmouseup",
        "onmousewheel",
        "onoffline",
        "ononline",
        "onpagehide",
        "onpageshow",
        "onpaste",
        "onpause",
        "onplay",
        "onplaying",
        "onpopstate",
        "onprogress",
        "onratechange",
        "onreset",
        "onresize",
        "onscroll",
        "onsearch",
        "onseeked",
        "onseeking",
        "onselect",
        "onshow",
        "onstalled",
        "onstorage",
        "onsubmit",
        "onsuspend",
        "ontimeupdate",
        "ontoggle",
        "onunload",
        "onvolumechange",
        "onwaiting",
        "onwheel",
        "optgroup",
        "option",
        "output",
        "param",
        "parent",
        "placeholder",
        "pre",
        "preceding-sibling::",
        "preceding::",
        "progress",
        "rp",
        "rt",
        "ruby",
        "samp",
        "script",
        "section",
        "select",
        "self",
        "sibling::",
        "small",
        "source",
        "span",
        "spellcheck",
        "src",
        "strike",
        "string",
        "strong",
        "style",
        "sub",
        "summary",
        "sup",
        "svg",
        "tabindex",
        "table",
        "target",
        "tbody",
        "td",
        "template",
        "text",
        "textarea",
        "tfoot",
        "th",
        "thead",
        "time",
        "timeStamp",
        "title",
        "tr",
        "track",
        "transitionend",
        "translate",
        "tt",
        "type",
        "ul",
        "value",
        "var",
        "video",
        "wbr",
        "width",
    ];
    $.isDownShift = false;
    $.preCmd = null;
    $.currDoc = null;
    $.shiftCode = 16; //shift按键码
    $.isClassList = [];
    $searchInput = null;
    $autocomplete = null;
    $selectedItem = 0;

    jQuery.fn.isChildAndSelfOf = function (b) {
        return this.closest(b).length > 0;
    };
    $.result = {};
    $.currentInput = "";
    $.currStrat = $.currentInput.length;

    //直接注入复制iframe
    let copyIframe = document.createElement("iframe");
    copyIframe.id = "xpathCopyIframe";
    copyIframe.style.display = "none";

    input = document.createElement("textarea");
    input.id = "xpathCopyInput";
    input.style.height = "0px";
    input.style.width = "0px";

    document.body.appendChild(copyIframe);

    let iframeBody =
        document.querySelector("#xpathCopyIframe").contentDocument.body;
    iframeBody.appendChild(input);

    /**
     * 没有数据时清理元素
     */
    let clearEls = function () {
        $("#xpath-results").val("");
        $("#tagName").text("");
        $("#node-count").text(0);

        let liEls = document.querySelectorAll(".xpath-li");
        for (let i = 0; i < liEls.length; i++) {
            liEls[i].innerText = "";
        }

        let titleEls = document.querySelectorAll("div.xpath-title");
        for (let i = 0; i < titleEls.length; i++) {
            titleEls[i].innerText = "";
        }

        let imgEls = document.querySelectorAll("img");
        for (let i = 0; i < imgEls.length; i++) {
            imgEls[i].classList.add("xpath-img-show");
        }
    };

    let getIndex = function (node) {
        let i = 1;
        let tagName = node.tagName.toLowerCase();
        while (node.previousSibling) {
            node = node.previousSibling;
            node.nodeType === 1 && tagName == node.tagName.toLowerCase() && i++;
        }
        return i;
    };

    //css选择器  绝对路径
    let generateSelector = function (element) {
        let index, pathSelector, localName;

        if (element == "null") throw "not an dom reference";
        // call getIndex function
        index = getIndex(element);

        while (element.tagName) {
            // selector path
            pathSelector =
                element.localName + (pathSelector ? ">" + pathSelector : "");
            element = element.parentNode;
        }
        // selector path for nth of type
        pathSelector = pathSelector + `:nth-of-type(${index})`;
        return pathSelector;
    };

    //css短路径
    let getShortCSSPath = function (el) {
        if (!(el instanceof Element)) return;
        let path = [];
        while (el.nodeType === Node.ELEMENT_NODE) {
            let selector = el.nodeName.toLowerCase();
            if (el.id) {
                if (parseInt(el.id)) {
                    selector += '[id="' + el.id + '"]';
                } else {
                    selector += "#" + el.id;
                }
                path.unshift(selector);
                break;
            } else {
                let sib = el,
                    nth = 1;
                while ((sib = sib.previousElementSibling)) {
                    if (sib.nodeName.toLowerCase() == selector) nth++;
                }
                if (nth != 1) selector += ":nth-of-type(" + nth + ")";
            }
            path.unshift(selector);
            el = el.parentNode;
        }
        return path.join(" > ");
    };

    //获取唯一元素路径
    let getNodePath = function (element, parentPath, only) {
        let tagName = element.tagName.toLowerCase();
        if (element.id !== "" && only) {
            return "//*[@id='" + element.id + "']";
        }
        if (element == document.body) {
            return "/html/" + tagName;
        }
        let oldPath = "//" + tagName;
        let newPath = "//" + tagName;
        if (parentPath.length > 0) {
            newPath = parentPath + newPath;
        }
        let attrStr = "";
        if (element.attributes.length == 0) {
            if (xpathQuery(newPath).els.length == 1) {
                return newPath;
            }
        }
        if (
            element.textContent.indexOf("\n") == -1 &&
            filterSymbol(element.textContent) &&
            element.textContent.length < 18
        ) {
            if (element.attributes.length == 0) {
                attrStr += "text()='" + element.textContent + "'";
            } else {
                attrStr += "text()='" + element.textContent + "' and ";
            }
        }
        if (
            xpathQuery((newPath + `[${attrStr}]`).replace("and", "")).els
                .length == 1
        ) {
            return (newPath + `[${attrStr}]`).replace("and", "");
        }

        for (let i = 0; i < element.attributes.length; i++) {
            let attribute = element.attributes[i];
            let key = attribute.name;
            let val = attribute.value;

            if (key == "id") {
                continue;
            }
            if (key == "class") {
                if (val.trim().length > 0) {
                    let classTmp = "contains(class, {})";
                    let classList = val.split(" ");
                    for (let j = 0; j < classList.length; j++) {
                        if (classList[j].trim()) {
                            if (j == classList.length - 1) {
                                attrStr += classTmp.replace("{}", classList[j]);
                            } else {
                                attrStr +=
                                    classTmp.replace("{}", classList[j]) +
                                    " and ";
                            }
                        }
                    }
                } else {
                    attrStr += "@" + key + " ";
                }
            } else if (val.length < 18 && val.trim()) {
                if (attrStr.length > 0) {
                    attrStr += " and @" + key + "='" + val + "' ";
                }
            } else if (attrStr.length > 0) {
                attrStr += " and @" + key + " ";
            } else {
                if (element.attributes.length - 1 == i && attrStr) {
                    attrStr += "@" + key + " and ";
                } else {
                    attrStr += "@" + key;
                }
            }
            if (attrStr && i == 0) {
                newPath += "[{}]";
                oldPath += "[{}]";
            }
            if (only) {
                if (
                    xpathQuery(newPath.replace("{}", attrStr.trim())).els
                        .length == 1
                ) {
                    return newPath.replace("{}", attrStr.trim());
                } else if (
                    parentPath.length > 0 &&
                    xpathQuery(
                        parentPath +
                            oldPath.replace("{}", attrStr.trim()).slice(1)
                    ).els.length == 1
                ) {
                    return (
                        parentPath +
                        oldPath.replace("{}", attrStr.trim()).slice(1)
                    );
                }
            }
        }
        if (parentPath.length > 0 && !only) {
            parentPath + oldPath.replace("{}", attrStr.trim()).slice(1);
        }
        if (!only) {
            return newPath.replace("{}", attrStr.trim());
        }
        return null;
    };

    //获取属性父元素唯一元素路径
    let getParentPath = function (element) {
        let parentEl = element.parentElement;
        while (parentEl) {
            result = getNodePath(parentEl, "", true);
            if (result) return result;
            parentEl = parentEl.parentElement;
        }
        return null;
    };

    //获取兄弟节点属性唯一元素路径
    let getAttrFollowingPath = function (element) {
        let nextEl = element.nextElementSibling;
        let nextNum = 1;
        while (nextEl) {
            if ((nextAttrPath = getNodePath(nextEl, "", true))) {
                return nextAttrPath + "/preceding-sibling::*[" + nextNum + "]";
            }
            if ((vaguePath = containsXpath(nextEl))) {
                return vaguePath + "/preceding-sibling::*[" + nextNum + "]";
            }
            nextEl = nextEl.nextElementSibling;
            nextNum++;
        }

        let preEl = element.previousElementSibling;
        let preNum = 1;
        while (preEl) {
            if ((preAttrPath = getNodePath(preEl, "", true))) {
                return preAttrPath + "/following-sibling::*[" + preNum + "]";
            }
            if ((vaguePath = containsXpath(preEl))) {
                return vaguePath + "/following-sibling::*[" + preNum + "]";
            }
            preEl = preEl.previousElementSibling;
            preNum++;
        }
        return null;
    };

    //xpath属性路径
    let readAttributesXPath = function (element) {
        //匹配当前路径
        let currPath = getNodePath(element, "", true);

        let parentRes = null;
        if (currPath != null) {
            return currPath;
        }
        //匹配父路径
        parentRes = getParentPath(element);
        if (parentRes) {
            return getNodePath(element, parentRes, true);
        }
    };

    //xpath全路径readAllXPath
    let readAllXPath = function (element) {
        let xpath = "";
        for (; element && element.nodeType == 1; element = element.parentNode) {
            let id =
                $(element.parentNode).children(element.tagName).index(element) +
                1;
            id > 1 ? (id = "[" + id + "]") : (id = "");
            xpath = "/" + element.tagName.toLowerCase() + id + xpath;
        }
        return xpath;
    };

    //过滤特殊字符
    let filterSymbol = function (queryText) {
        return (
            queryText.charCodeAt(0) < 57344 || queryText.charCodeAt(0) > 63743
        );
    };

    let getSearchFunc = function (xpath, tagName, func, queryText) {
        if (func == "text") {
            xpath = xpath + tagName + "[contains(text(), '{}')]";
        } else {
            xpath = xpath + tagName + "[contains(string(), '{}')]";
        }
        if (queryText.indexOf("'") > -1) xpath = xpath.replaceAll("'", '"');
        return xpath.replace("{}", queryText);
    };

    //xpath相对路径
    let readXPath = function (element) {
        if (element.id !== "") {
            return "//*[@id='" + element.id + "']";
        }
        if (element == document.body) {
            return "/html/" + element.tagName.toLowerCase();
        }
        let ix = 1,
            siblings = element.parentNode.childNodes;
        for (let i = 0, l = siblings.length; i < l; i++) {
            let sibling = siblings[i];
            if (sibling == element) {
                return (
                    arguments.callee(element.parentNode) +
                    "/" +
                    element.tagName.toLowerCase() +
                    "[" +
                    ix +
                    "]"
                );
            } else if (
                sibling.nodeType == 1 &&
                sibling.tagName == element.tagName
            ) {
                ix++;
            }
        }
    };

    //组合路径
    let combinationPath = function (element) {
        if ((result = readAttributesXPath(element))) {
            return result;
        }
        if ((containsPath = containsXpath(element))) {
            return containsPath;
        }

        if ((attrFollowingPath = getAttrFollowingPath(element))) {
            return attrFollowingPath;
        }
        return readAllXPath(element);
    };

    /**
     * xpath模糊匹配路径
     * @param element
     * @returns {*|null}
     */
    let containsXpath = function (element) {
        let tagName = element.tagName.toLowerCase();
        let xpath = "//";
        let queryXpath = readXPath(element);
        let headings = document.evaluate(
            queryXpath,
            document,
            null,
            XPathResult.ANY_TYPE,
            null
        );
        let next = headings.iterateNext();
        let queryText = "";
        while (next) {
            queryText += next.textContent;
            next = headings.iterateNext();
        }

        queryText = queryText.trim();
        if (queryXpath && filterSymbol(queryText)) {
            if (queryText.length > 18) queryText = queryText.slice(0, 18);
            if (queryText.indexOf("\n") > -1)
                queryText = queryText.slice(0, queryText.indexOf("\n"));

            let textXpath = getSearchFunc(xpath, tagName, "text", queryText);
            //匹配当前路径
            if (xpathQuery(textXpath).els.length == 1) {
                return textXpath;
            } else if ((parentRes = getParentPath(element))) {
                //匹配属性父路径
                if (xpathQuery(parentRes + textXpath).els.length == 1) {
                    return parentRes + textXpath;
                }
            }

            let stringXpath = getSearchFunc(
                xpath,
                tagName,
                "string",
                queryText
            );
            if (xpathQuery(stringXpath).els.length == 1) {
                return stringXpath;
            } else if ((parentRes = getParentPath(element))) {
                if (xpathQuery(parentRes + stringXpath).els.length == 1) {
                    return parentRes + stringXpath;
                }
            }
        }

        return null;
    };

    /**
     * 路径删除背景class
     * @param path
     * @returns {*}
     */
    let removeClass = function (path) {
        let strartIndex = path.indexOf("lt-query-el-background");
        if (strartIndex != -1) {
            return path.slice(0, strartIndex - 1);
        }
        return path;
    };

    /**
     * 监听鼠标移动， 获取页面上元素定位path
     */
    document.addEventListener("mousemove", function (event) {
        let doc = ($.currDoc = event.toElement);
        let popup = document.querySelector("#xpathPupop");
        if ($.isDownShift && doc && popup) {
            let queryEl = event.toElement;
            let data = { paths: [], status: "ok", text: "" };
            $.preCmd != null &&
                $.isDownShift &&
                clearElColor($.preCmd, $.isClassList);
            //获取css路径
            let cssPath1 = generateSelector(queryEl);

            let cssPath2 = removeClass(getShortCSSPath(queryEl));

            let xpath1 = combinationPath(queryEl);

            let xpath2 = readXPath(queryEl);

            let result = xpathQuery(xpath2);
            setBackgroundColor(result.els);

            $.preCmd = xpath2;
            $.isClassList = result.isClassList;
            data.tagName = queryEl.tagName;
            data.paths.push({ path: xpath2, type: "xpath" });
            data.paths.push({ path: xpath1, type: "xpath" });
            data.paths.push({ path: cssPath1, type: "css" });
            data.paths.push({ path: cssPath2, type: "css" });
            data.text = result.text;
            data.count = result.count;
            putPath(data);

            //监听鼠标移动是否需要变动窗口
            let sendData = {};
            sendData.cmd = "position";
            sendData.isDownShift = $.isDownShift;
            changeIframe(sendData);
        }
    });

    /**
     * shift按下
     */
    document.addEventListener("keydown", function sendKeyCodeDown(event) {
        let e = event || window.event || arguments.callee.caller.arguments[0];
        if (e && e.keyCode == $.shiftCode) {
            $.isDownShift = true;
        }
    });

    /**
     * 监听鼠标抬起
     */
    document.addEventListener("keyup", function sendKeyCodeUp(event) {
        let e = event || window.event || arguments.callee.caller.arguments[0];
        if (e && e.keyCode == $.shiftCode) {
            $.isDownShift = false;
        }
    });

    /**
     * 监听页面离焦事件
     */
    document.onmouseout = function (event) {
        if (event.toElement == null) {
            $.isDownShift = false;
        }
    };

    /**
     * 控制弹窗显示关闭
     * @param data
     */
    let clickPupop = function (data) {
        if ($.preCmd) {
            clearElColor($.preCmd, $.isClassList);
        }
        let local = data.local;
        let pupop = document.querySelector("#xpath-body");

        if (pupop) {
            pupop.remove();
            return;
        }

        let body = document.querySelector("body");
        let iframe = document.createElement("div");
        iframe.setAttribute("position", true);
        // iframe.src = local + "/iframe.html";
        iframe.innerHTML = `
        <div id="xpathPupop">
            <div class="xpath-search-name-box">
                <div>查询</div>
                <div id="xpathTagName"></div>
            </div>
            <div id="paths">
                <div class="xpath-path-group">
                    <div name="xpathTitle" class="xpath-title"></div>
                    <div class="xpath-li" style="cursor: url(${data.url}/assets/iota16.png), auto;"></div>
                    <image class="xpath-img-show xpath-img" name="xpathEdit" src="${data.url}/assets/edit.png"></image>
                    <image class="xpath-img-show xpath-img" name="xpathCopyPath" src="${data.url}/assets/copy.png"></image>
                </div>
                <div class="xpath-path-group">
                    <div name="xpathTitle" class="xpath-title"></div>
                    <div class="xpath-li" style="cursor: url(${data.url}/assets/iota16.png), auto;"></div>
                    <image class="xpath-img-show xpath-img" name="xpathEdit" src="${data.url}/assets/edit.png"></image>
                    <image class="xpath-img-show xpath-img" name="xpathCopyPath" src="${data.url}/assets/copy.png"></image>
                </div>
                <div class="xpath-path-group">
                    <div name="xpathTitle" class="xpath-title"></div>
                    <div class="xpath-li" style="cursor: url(${data.url}/assets/iota16.png), auto;"></div>
                    <image class="xpath-img-show xpath-img" name="xpathEdit" src="${data.url}/assets/edit.png"></image>
                    <image class="xpath-img-show xpath-img" name="xpathCopyPath" src="${data.url}/assets/copy.png"></image>
                </div>
                <div class="xpath-path-group">
                    <div name="xpathTitle" class="xpath-title"></div>
                    <div class="xpath-li" style="cursor: url(${data.url}/assets/iota16.png), auto;"></div>
                    <image class="xpath-img-show xpath-img" name="xpathEdit" src="${data.url}/assets/edit.png"></image>
                    <image class="xpath-img-show xpath-img" name="xpathCopyPath" src="${data.url}/assets/copy.png"></image>
                </div>
            </div>

            <div id="xpath-search">
                <input type="text" class="xpath-query-input" style="cursor: url(${data.url}/assets/iota16.png), auto;" id="query"></input>
            </div>
        </div>
        <div id="xpath-results-box">
            <div class="xpath-result-group">
                <div class="xpath-box-name">元素节点(<span id="node-count"></span>)</div>
                <button id="xpath-text-copy">复制</button>
            </div>
            <textarea id="xpath-results" style="cursor: url(${data.url}/assets/iota16.png), auto;" readonly="readonly"></textarea>
        </div>
        `;
        iframe.classList.add("lt-open-query");
        iframe.id = "xpath-body";
        body.appendChild(iframe);

        //监听输入
        $(".xpath-query-input").on("input propertychange", changeInput);

        //编辑事件
        let editEls = document.querySelectorAll("img[name=xpathEdit]");
        for (let i = 0; i < editEls.length; i++) {
            editEls[i].onmousedown = function () {
                editEls[i].classList.add("xpath-click-copy");
                setTimeout(
                    function (el) {
                        el.classList.remove("xpath-click-copy");
                    },
                    100,
                    editEls[i]
                );
            };
            editEls[i].onclick = function () {
                let textNode = editEls[i].parentNode.querySelector(".xpath-li");
                $(".xpath-query-input").val(textNode.innerText);
                $(".xpath-query-input").trigger("input");
                clearDropDown();
            };
        }

        //处理icon 复制事件
        let copyEls = document.querySelectorAll("img[name=xpathCopyPath]");
        for (let i = 0; i < copyEls.length; i++) {
            copyEls[i].onmousedown = function () {
                copyEls[i].classList.add("xpath-click-copy");
                setTimeout(
                    function (el) {
                        el.classList.remove("xpath-click-copy");
                    },
                    100,
                    copyEls[i]
                );
            };
            copyEls[i].onclick = function () {
                let textNode = copyEls[i].parentNode.querySelector(".xpath-li");
                copyText(textNode.innerText);
            };
        }

        //注册复制事件
        $("#xpath-text-copy").click(function () {
            if ($("#xpath-results").val()) {
                $("#xpath-text-copy").text("复制成功");
                let textEl = $("#xpath-results");
                copyText(textEl.val());
                setTimeout(function () {
                    $("#xpath-text-copy").text("复制");
                }, 300);
            }
        });

        //取得div层
        let $search = $("#xpath-search");
        //取得输入框JQuery对象
        $searchInput = $search.find(".xpath-query-input");
        //关闭浏览器提供给输入框的自动完成
        $searchInput.attr("autocomplete", "off");
        //创建自动完成的下拉列表，用于显示服务器返回的数据,插入在搜索按钮的后面，等显示的时候再调整位置
        $autocomplete = $('<div class="xpath-autocomplete"></div>')
            .hide()
            .insertAfter(".xpath-query-input");

        //注册事件，当输入框失去焦点的时候清空下拉列表并隐藏
        $searchInput.blur(function () {
            setTimeout(clearDropDown, 500);
        });

        $searchInput
            .click(searchInputCheck)
            .keyup(searchInputKeyup)
            .keypress(searchInputKeypress)
            .keydown(searchInputKeydown);
        //下拉列表中高亮的项目的索引，当显示下拉列表项的时候，移动鼠标或者键盘的上下键就会移动高亮的项目，想百度搜索那样
    };

    /**
     * 变动窗口
     * @param doc
     */
    let elTransform = function (doc) {
        if (doc.getAttribute("position") == "true") {
            doc.classList.remove("lt-open");
            doc.classList.add("lt-down");
            doc.setAttribute("position", false);
        } else {
            doc.classList.remove("lt-down");
            doc.classList.add("lt-open");
            doc.setAttribute("position", true);
        }
    };

    /**
     * 判断是否需要变动窗口
     * @param data
     */
    let isChangePopup = function () {
        // flag 元素是否为弹窗子元素
        let flag = $($.currDoc).isChildAndSelfOf("#xpath-body");
        try {
            if (flag && $.isDownShift) {
                elTransform(document.querySelector("#xpath-body"));
                return;
            }
        } catch (err) {
            console.log(err);
        }
    };

    //清理背景颜色
    let clearElColor = function (preCmd, isClassList) {
        if (preCmd.indexOf("[@class='']") > -1) {
            preCmd = preCmd.replace(
                "[@class='']",
                "[@class='lt-query-el-background']"
            );
        }
        try {
            let preEls = document.querySelectorAll(preCmd);
            for (let i = 0; i < preEls.length; i++) {
                preEls[i].classList.remove("lt-query-el-background");
                isClassList &&
                    isClassList[i] == 0 &&
                    preEls[i].removeAttribute("class");
            }
            return true;
        } catch (err) {}
        try {
            let els = document.querySelectorAll(".lt-query-el-background");
            for (let i = 0; i < els.length; i++) {
                els[i].classList.remove("lt-query-el-background");
                isClassList &&
                    isClassList[i] == 0 &&
                    els[i].removeAttribute("class");
            }
            return true;
        } catch (err) {}

        try {
            let iter = document.evaluate(
                preCmd,
                document,
                null,
                XPathResult.ANY_TYPE,
                null
            );
            let next = iter.iterateNext();
            let nodeList = [];
            while (next) {
                nodeList.push(next);
                next = iter.iterateNext();
            }

            for (let i = 0; i < nodeList.length; i++) {
                nodeList[i].classList.remove("lt-query-el-background");
                isClassList &&
                    isClassList[i] == 0 &&
                    nodeList[i].removeAttribute("class");
            }
            return true;
        } catch (err) {
            return false;
        }
    };

    //元素设置背景颜色
    let setBackgroundColor = function (nodeList) {
        for (let i = 0; i < nodeList.length; i++) {
            nodeList[i].classList.add("lt-query-el-background");
        }
    };

    /**
     * 搜索css元素
     * @param query
     * @returns {{preCmd: string, count: number, isClassList: *[], text: string, els: *[]}}
     */
    let cssQuery = function (query) {
        let result = {
            text: "",
            count: 0,
            preCmd: "",
            els: [],
            isClassList: [],
        };
        try {
            let els = document.querySelectorAll(query);
            result.els = els;
            for (let i = 0; i < els.length; i++) {
                result.text += els[i].innerText + "\n\n";
            }
            if (result.text.length > 0) {
                result.count = els.length;
                result.preCmd = query;
                result.status = "text";
                $.preCmd = query;
            } else {
                result.status = "null";
            }
        } catch (err) {
            result.status = "null";
            return result;
        }
        return result;
    };

    /**
     * 搜索xpath元素
     * @param query
     * @returns {{preCmd: string, count: number, isClassList: *[], text: string, els: *[]}}
     */
    let xpathQuery = function (query) {
        let result = {
            text: "",
            count: 0,
            preCmd: "",
            els: [],
            isClassList: [],
        };
        try {
            let iter = document.evaluate(
                query,
                document,
                null,
                XPathResult.ANY_TYPE,
                null
            );
            let next = iter.iterateNext();
            let nodeList = [];
            while (next) {
                nodeList.push(next);
                result.isClassList.push(next.classList.length > 0 ? 1 : 0);
                if (next == document) throw "element is docment";
                result.text += next.textContent + "\n\n";
                next = iter.iterateNext();
            }
            result.els = nodeList;
            if (result.text.length > 0) {
                result.count = nodeList.length;
                result.preCmd = query;
                result.status = "text";
                $.preCmd = query;
                return result;
            } else {
                result.status = "null";
                result.preCmd = query;
            }
        } catch (err) {
            result.preCmd = query;
            result.status = "null";
            return result;
        }
        return result;
    };

    /**
     * css or xpath 元素查找
     * @param data
     * @returns {{preCmd: string, sender: string, count: number, isClassList: *[], text: string, status: *}}
     */
    let query = function (data) {
        let result = cssQuery(data.query);
        if (result.text == "") {
            result = xpathQuery(data.query);
        }
        setBackgroundColor(result.els);
        //putPath();
        return {
            sender: "query",
            isClassList: result.isClassList,
            text: result.text,
            count: result.count,
            preCmd: result.preCmd,
            status: result.status,
        };
    };

    //接收消息
    chrome.runtime.onMessage.addListener(function (
        request,
        sender,
        sendResponse
    ) {
        let data = request.msg;
        data.cmd == "clickPupop" && clickPupop(data);
    });

    /**
     * 判断是否清理css, 以及窗口变动
     * @param data
     * @returns {{preCmd: string, sender: string, count: number, isClassList: [], text: string, status: (string|"fulfilled"|number|FontFaceSetLoadStatus|string|FontFaceLoadStatus|"rejected"|*)}}
     */
    let changeIframe = function (data) {
        //判断是否需要窗口转换位置
        data.cmd == "position" && isChangePopup();
        let clear =
            data.preCmd &&
            data.preCmd != "" &&
            data.cmd != "position" &&
            clearElColor(data.preCmd, data.isClassList);
        //清理颜色css
        clear =
            $.preCmd &&
            $.preCmd != "" &&
            data.cmd != "position" &&
            clearElColor($.preCmd, data.isClassList);

        // clear && sendResponse({ status: "null", sender: "onMessage" });

        // !data.query && sendResponse({ status: "null", sender: "onMessage" });
        if (data.query) {
            rsp = query(data);
            return rsp;
        }
    };

    /**
     * iframe接收消息
     */
    chrome.runtime.onMessage.addListener(function (
        request,
        sender,
        sendResponse
    ) {
        let data = request.msg;
        data.status == "ok" && putPath(data);
        sendResponse({ status: "ok" });
    });

    /**
     *监听到输入后的动作
     */
    let changeInput = function () {
        clearDropDown();
        let query = $(this).val();
        $.currentInput = query;
        if (!query) {
            $.currentInput = "";
            clearDropDown();
        }
        let inputEl = document.querySelector(".xpath-query-input");
        $.currStrat = inputEl.selectionEnd;
        ajax_request(query);
        let data = {};
        data.query = query;
        data.preCmd = $.preCmd;
        $.preCmd = "";
        let rsp = changeIframe(data);
        if (rsp) {
            inputText(rsp);
            $.preCmd = rsp.preCmd;
        }
    };

    /**
     * 复制文本
     * @param text
     * @param count
     */
    function copyText(text, count) {
        let input;
        if (navigator.clipboard) {
            // 如果浏览器兼容该 API
            navigator.clipboard.writeText(text).catch(function (err) {
                console.log(err);
            });
        } else {
            let iframeDocument =
                document.querySelector("#xpathCopyIframe").contentDocument;

            input = iframeDocument.querySelector("#xpathCopyInput");
            input.value = text;
            input.select();
            iframeDocument.execCommand("copy") &&
                iframeDocument.execCommand("copy");
        }
    }

    /**
     * 展示页面路径
     * @param data
     */
    function putPath(data) {
        let paths = data.paths;
        let els = document.querySelectorAll(".xpath-li");
        let titleEls = document.querySelectorAll("div[name=xpathTitle]");

        clearEls();
        for (let i = 0; i < paths.length; i++) {
            els[i].innerText = paths[i].path;
            titleEls[i].innerText = paths[i].type;
        }
        let imgEls = document.querySelectorAll("img");
        for (let i = 0; i < imgEls.length; i++) {
            imgEls[i].classList.remove("xpath-img-show");
        }
        $(".xpath-query-input").val(paths[0].path);
        $("#tagName").text("标签类型:  " + data.tagName);
        $.currentInput = paths[0].path;
        inputText(data);
    }

    /**
     * 展示响应区域的文本
     * @param data
     */
    function inputText(data) {
        if (data) {
            $("#xpath-results").val(data.text);
            $("#node-count").text(data.count);
        }
    }

    /**
     * 清空下拉列表的内容并且隐藏下拉列表区
     */
    let clearDropDown = function () {
        $autocomplete.empty().hide();
    };

    /**
     * 设置下拉项的高亮背景
     * @param item
     */
    let setSelectedItem = function (item) {
        //更新索引变量
        $selectedItem = item;
        let liLength = $autocomplete.find("li").length;
        if ($selectedItem < 0) {
            $selectedItem = liLength - 1;
        }
        if ($selectedItem > liLength - 1) {
            $selectedItem = 0;
        }
        $autocomplete
            .find("li")
            .removeClass("xpath-highlight")
            .eq($selectedItem)
            .addClass("xpath-highlight");
    };

    /**
     * 分词重组
     * @param {分词对象} obj
     */
    let reorganization = function (obj) {
        let input = "";
        for (let index = 0; index < obj.data.length; index++) {
            const element = obj.data[index];
            if (index == obj.index) {
                input += "{{lt-replace}}";
            } else {
                input += element;
            }
        }
        return input;
    };

    /**
     *
     * @param {分词字符串} string
     * @returns
     */
    let participle = function (string) {
        let index = document.querySelector(".xpath-query-input").selectionStart;
        let re = /\b/g;
        let re2 = /[A-Z]/g;

        function convert(propertyName) {
            function upperToLower(match) {
                return match.toLowerCase();
            }

            return propertyName.replace(re2, upperToLower);
        }

        string = convert(string);
        let output = [];
        output = string.split(re);
        let output2 = [];
        for (let i = 0; i < output.length; i++) {
            if (output[i] !== "," && output[i] !== ";" && output[i] !== ".")
                output2.push(output[i]);
        }

        let itemIndex = 0;
        for (let i = 0; i < output.length; i++) {
            const element = output[i];
            itemIndex += element.length;
            if (itemIndex >= index) {
                itemIndex = i;
                break;
            }
            if (i == output.length - 1 && itemIndex < index) {
                itemIndex = output.length - 1;
            }
        }
        let result = {};
        result.data = output;
        result.index = itemIndex;
        return result;
    };

    /**
     * 添加提示框内容
     * @param val
     */
    let ajax_request = function (val) {
        let result = participle(val);
        $.result = result;
        let data = [];
        if (val) {
            data = $.keywords.filter((key) => {
                if (key == result.data[result.index]) return;
                return key.indexOf(result.data[result.index]) == 0;
            });
        }
        if (data.length > 5) data = data.splice(0, 5);
        data.reverse();
        if (data.length) {
            //遍历data，添加到自动完成区
            $.each(data, function (index, term) {
                //创建li标签,添加到下拉列表中
                $("<li></li>")
                    .text(term)
                    .prependTo($autocomplete)
                    .addClass("xpath-clickable")
                    .hover(
                        function () {
                            //下拉列表每一项的事件，鼠标移进去的操作
                            $(this).siblings().removeClass("xpath-highlight");
                            $(this).addClass("xpath-highlight");
                            $selectedItem = index;
                        },
                        function () {
                            //下拉列表每一项的事件，鼠标离开的操作
                            $(this).removeClass("xpath-highlight");
                            //当鼠标离开时索引置-1，当作标记
                            $selectedItem = -1;
                        }
                    )
                    .click(function () {
                        //鼠标单击下拉列表的这一项的话，就将这一项的值添加到输入框中
                        $searchInput.val(term);
                        //清空并隐藏下拉列表
                        $autocomplete.empty().hide();
                    });
            }); //事件注册完毕
            //设置下拉列表的位置，然后显示下拉列表
            let inputEl = $(".xpath-query-input");
            let lis = $(".xpath-autocomplete li");
            $autocomplete.css("width", "20%");
            $autocomplete.css({
                position: "relative",
                left: 0 + "px",
                bottom: 18 * lis.length + inputEl.height() + 5,
                "background-color": "#fff",
            });
            setSelectedItem(data.length - 1);
            //显示下拉列表
            $autocomplete.show();
        } else {
            clearDropDown();
        }
    };
    /**
     * 输入框点击事件
     */
    let searchInputCheck = function (event) {
        let inputEl = document.querySelector(".xpath-query-input");
        if (inputEl.selectionStart == 0) {
            inputEl.selectionStart = $.currStrat;
            inputEl.selectionEnd = $.currStrat;
        } else {
            $.currStrat = inputEl.selectionEnd;
        }
    };

    /**
     * 输入框键盘抬起事件
     * @param event
     */
    let searchInputKeyup = function (event) {
        //字母数字，退格，空格
        let inputEl = document.querySelector(".xpath-query-input");
        if (event.keyCode == 38) {
            //上键
            //selectedItem = -1 代表鼠标离开
            if ($selectedItem == -1) {
                setSelectedItem($autocomplete.find("li").length - 1);
            } else {
                //索引减1
                setSelectedItem($selectedItem - 1);
            }
            backFillText(inputEl);
        } else if (event.keyCode == 40) {
            //下
            //selectedItem = -1 代表鼠标离开
            if ($selectedItem == -1) {
                setSelectedItem(0);
            } else {
                //索引加1
                setSelectedItem($selectedItem + 1);
            }
            backFillText(inputEl);
        }
        if (event.keyCode == 37 || event.keyCode == 39 || event.keyCode == 8) {
            let inputEl = document.querySelector(".xpath-query-input");
            $.currStrat = inputEl.selectionEnd;
        }
    };

    /**
     * 输入框键盘输入事件
     * @param event
     */
    let searchInputKeypress = function (event) {
        let inputEl = document.querySelector(".xpath-query-input");
        //enter键
        if (event.keyCode == 13) {
            //列表为空或者鼠标离开导致当前没有索引值
            backFillText(inputEl);
            //隐藏下拉框
            $searchInput.trigger("input");
            $autocomplete.empty().hide();
        }
    };

    /**
     * 输入键盘抬起事件
     * @param event
     */
    let searchInputKeydown = function (event) {
        //esc键
        if (event.keyCode == 38) {
            event.preventDefault();
            return false;
        }
        if (event.keyCode == 27) {
            $autocomplete.empty().hide();
            event.preventDefault();
        }
    };

    /**
     * 回填文本
     */
    let backFillText = function (inputEl) {
        if ($autocomplete.find("li").length == 0 || $selectedItem == -1) {
            return;
        }
        let input = reorganization($.result);
        //重新回填
        let selectStr = $autocomplete.find("li").eq($selectedItem).text();
        $.currStrat = input.indexOf("{{lt-replace}}");
        input = input.replace("{{lt-replace}}", selectStr);
        let index = input.indexOf(selectStr, $.currStrat) + selectStr.length;

        $searchInput.val(input);

        inputEl.selectionEnd = index;
        inputEl.selectionStart = index;
        $.currStrat = index;
    };
});
